package com.xreal.netty.server;

import com.xreal.netty.server.handler.CustomServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * @author yangzhongming
 * @desc netty 服务端 示例
 * @date 2022/6/14
 */
@SuppressWarnings("unused")
public class NettyServer {

    //监听端口
    private final int port;

    public NettyServer(int port) {
        this.port = port;
    }

    /**
     * 开启服务--监听端口
     */
    public void listen() {

        EventLoopGroup bossGroup = null;
        EventLoopGroup workerGroup = null;
        try {
            //创建服务端--类似serverSocket 创建对应的服务器
            //创建服务端的启动对象，设置参数
            ServerBootstrap server = new ServerBootstrap();


            //给服务器端绑定 主线程(boosGroup) 和  子线程(workerGroup)
            bossGroup = new NioEventLoopGroup();
            workerGroup = new NioEventLoopGroup();
            server.group(bossGroup, workerGroup)
                    //设置服务端通道实现类型 (通道channel的类型)
                    .channel(NioServerSocketChannel.class)
                    //(详细请看README)backlog 用于构造服务端套接字ServerSocket对象，标识当服务器请求处理线程全满时，用于临时存放已完成三次握手的请求的队列的最大长度。
                    .option(ChannelOption.SO_BACKLOG, 128)
                    //保持客户端长连接
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    //初始化通道对象
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) {
                            //通道对象--责任链模式（Chain of Responsibility Pattern）
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            //协议处理
                            pipeline.addLast(new CustomServerHandler());
                        }
                    });
            System.out.println("服务端准备就绪：监听端口：" + this.port);
            //绑定端口，并且阻塞，等待所有异步任务完毕--保证启动后不会立即结束
            ChannelFuture channelFuture = server.bind(this.port).sync();

            //等待关闭请求发生后，优雅地关闭服务
            channelFuture.channel().closeFuture().sync();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //释放资源
            if (bossGroup != null) {
                bossGroup.shutdownGracefully();
            }
            if (workerGroup != null) {
                workerGroup.shutdownGracefully();
            }
        }


    }
}
